package eu.briano.suirvellancecamera.service;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;

import eu.briano.suirvellancecamera.Log;
import eu.briano.suirvellancecamera.R;
import eu.briano.suirvellancecamera.Utils;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;

import android.widget.Toast;

public class UploadService extends Service  {
	private NotificationManager mNM;
	private int NOTIFICATION = R.string.background_service_started;

	private DropboxAPI<AndroidAuthSession> mDBApi;




	public class LocalBinder extends Binder {
		public UploadService getService() {
			return UploadService.this;
		}
	}

	Timer timer = null;
	protected boolean uploadRunning = false;

	private final IBinder mBinder = new LocalBinder();

	@Override
	public void onCreate() {
		mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		showNotification();
		Log.i(Utils.logName, "Service onCreate");
		timer = new Timer();
		Calendar c = Calendar.getInstance();
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MINUTE, 0);
		Date startDate = c.getTime();

		mDBApi = Utils.dropBoxConnect(this);


		TimerTask task = new TimerTask() {
			@Override
			public void run() {
				processAndUploadImages();
			}


		};

		timer.scheduleAtFixedRate(task, startDate,
				Utils.uploaderPollingPeriod);

	}

	public void processAndUploadImages() {
		if (uploadRunning) {
			Log.i(Utils.logName, "UploadService task skipped " + this.toString());
			return;
		}
		uploadRunning = true;



		try {
			Log.i(Utils.logName, "UploadService task start " + this.toString());
			convertImages();


			if (somethingToSend()) {

				PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
				PowerManager.WakeLock wl = pm.newWakeLock(
						PowerManager.FULL_WAKE_LOCK |
						PowerManager.ACQUIRE_CAUSES_WAKEUP
						, "YascWakeLock");

				if (wl != null &&
						!wl.isHeld()){ 
					wl.acquire();
					Log.d(Utils.logName, "wake locked");
				}

				try {
					WifiManager wifi;
					wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
					//WifiInfo wifiInfo = wifi.getConnectionInfo();  // extra if you want connection info
					wifi.setWifiEnabled(true);
				} catch (Throwable e) {
					Log.e(Utils.logName, "UploadService error opening wifi  ", e);
				} 


				try {
					Log.d(Utils.logName, "sleep waiting connection");
					Thread.sleep(60*1000);
					sendImages();
				} catch (Throwable e) {
					Log.e(Utils.logName, "UploadService error on sending  ", e);
				}

				if (wl != null &&
						wl.isHeld()) 
					wl.release();

			} else {
				Log.i(Utils.logName, "UploadService nothing to send ");
			}
			Log.i(Utils.logName, "UploadService task end " + this.toString());
		} catch (Throwable e) {
			Log.e(Utils.logName, "UploadService error on spooling files ", e);
		}
		uploadRunning = false;
	}


	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(Utils.logName, "Service Received start id " + startId + ": "
				+ intent);
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
		mNM.cancel(NOTIFICATION);
		Toast.makeText(this, R.string.background_service_stopped,
				Toast.LENGTH_SHORT).show();
		if (timer != null) {
			timer.cancel();
			timer = null;
		}
		Log.i(Utils.logName, "Service onDestroy");
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.i(Utils.logName, "Service binded");
		return mBinder;
	}

	public void reloadDropBoxConf() {
		mDBApi = Utils.dropBoxConnect(this);
	}






	private void dropBoxPutFile(File srcFile, String prefix, String postFix,
			Calendar now, boolean deleteAfter) {
		if (mDBApi != null && mDBApi.getSession().isLinked()) {
			try {
				FileInputStream inputStream = new FileInputStream(srcFile);
				String destFileName = Utils.getDropBoxFileName(now, postFix,
						prefix);
				mDBApi.putFile(destFileName, inputStream, srcFile.length(),
						null, null);

				Log.v(Utils.logName, "UploadService file putted "+ srcFile.getName() + " "  + destFileName);
				srcFile.delete();
			} catch (Throwable e) {
				Log.e(Utils.logName, "UploadService error on put for:", e);
			}
		} else {
			Log.d(Utils.logName, "UploadService not connected");
		}
	}

	private boolean somethingToSend() {
		File imageDir = new File(Utils.getSendFileBasePath());
		if (imageDir.isDirectory()) {
			return imageDir.listFiles().length > 0;
		}
		return false;
	}


	private void sendImages() {
		File imageDir = new File(Utils.getSendFileBasePath());
		if (imageDir.isDirectory()) {
			File[] files = imageDir.listFiles();
			Arrays.sort(files);
			for (File file : files) {
				if (   !file.getName().contains("-")
						|| !file.getName().contains("processed")
						)
					continue;

				long timestamp = Utils.parseFormattedTimestamp(file.getName());

				if (timestamp == 0)
					continue;

				Calendar now = Calendar.getInstance();
				now.setTimeInMillis(timestamp);


				if (file.getName().contains("map"))
					dropBoxPutFile(file, "map/", "", now, true);
				else
					dropBoxPutFile(file, "", "", now, true);
			}
		}

	}

	private void convertImages() {
		File imageDir = new File(Utils.getSendFileBasePath());
		if (imageDir.isDirectory()) {
			boolean hasFiles = true;
			while (hasFiles) {
				hasFiles = false;
				File[] files = imageDir.listFiles(new FileFilter() {
					private int limit = 50;
					@Override
					public boolean accept(File file) {
						boolean ok = 
								file.getName().contains("-")
								&& !( file.getName().contains("processed")
										|| file.getName().contains("map")	
										|| file.getName().contains("txt")
										);
						if (ok )
							ok = (limit-- > 0 ); 
						return ok ;
					}
				});
				Log.v(Utils.logName, "UploadService found "+files.length+ " files ");
				Arrays.sort(files);
				for (File file : files) {
					try {
						/*
						if (!file.getName().contains("-")
							|| file.getName().contains("processed")
							|| file.getName().contains("map")
							|| file.getName().contains("txt"))
						continue;
						 */
						long timestamp = Utils.parseFormattedTimestamp(file.getName());
						if (timestamp == 0)
							continue;
						Calendar imageTs = Calendar.getInstance();
						imageTs.setTimeInMillis(timestamp);

						String mapFile = file.getAbsolutePath() + ".map";

						Bitmap immutableBitmap = BitmapFactory.decodeFile(file
								.getAbsolutePath());
						if (immutableBitmap != null) {
							Bitmap mutableBitmap = immutableBitmap.copy(
									Bitmap.Config.ARGB_8888, true);
							immutableBitmap.recycle();
							immutableBitmap = null;
							Canvas c = new Canvas(mutableBitmap);

							String text = imageTs.getTime().toGMTString();
							Paint p = new Paint();
							p.setColor(Color.BLACK);
							p.setAlpha(100);
							c.drawRoundRect(
									new RectF(0, 0, mutableBitmap.getWidth(), 30),
									0f, 0f, p);
							p.setColor(Color.WHITE);
							p.setTextSize(17);
							p.setAntiAlias(true);
							p.setTypeface(Typeface.SERIF);


							c.drawText(text, 10, 23, p);

							OutputStream os = new FileOutputStream(file.getAbsolutePath()+".processed");
							mutableBitmap.compress(Bitmap.CompressFormat.JPEG,
									Utils.imageQuality, os);
							os.flush();
							os.close();

							Bitmap map = BitmapFactory.decodeFile(mapFile);
							if (map != null) {
								p.setColor(Color.WHITE);
								p.setAlpha(128);

								c.drawBitmap(map, new Rect(0, 0, Utils.ipSize,
										Utils.ipSize),
										new Rect(0, 0, mutableBitmap.getWidth(),
												mutableBitmap.getHeight()), p);


								try {
									text = Utils.readFile(file.getAbsolutePath() + ".txt");
									c.drawText(text, 10, 44, p);
									new File  (file.getAbsolutePath() + ".txt").delete();
								} catch (Exception e) {
									Log.w(Utils.logName,"UploadService cannot print info ",e);
								}

								os = new FileOutputStream(mapFile+".processed");
								mutableBitmap.compress(Bitmap.CompressFormat.JPEG,
										Utils.imageQuality, os);
								map.recycle();
								map = null;
							}
							if (mutableBitmap != null)
								mutableBitmap.recycle();
							mutableBitmap = null;
							file.delete();
							new File(mapFile).delete();

							Log.v(Utils.logName, "UploadService file processed "+file.getName());

						}
					} catch (Throwable e) {
						Log.e(Utils.logName, "UploadService draw error", e);
					}

				}
			}
		}

	}



	private void showNotification() {
		Toast.makeText(this, R.string.background_service_started,
				Toast.LENGTH_SHORT).show();
		/*
		 * Notification notification = new Notification(R.drawable.icon, text,
		 * System.currentTimeMillis());
		 * 
		 * PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new
		 * Intent(this, SuirvellanceCameraActivity.class), 0);
		 * notification.setLatestEventInfo(this,
		 * getText(R.string.background_service_label), text, contentIntent);
		 * 
		 * mNM.notify(NOTIFICATION, notification);
		 */
	}

}
